import Panorama from '../view/Panorama';
import Animator from '../animate/Animator';
import Point from '../geometry/Point';

type State = 'pending' | 'active' | 'enable' | 'disable';

type BaseType = [number, (number | Point), (number | Point)?, (number | Point)?];

abstract class AbstractGesture<I extends BaseType> {
    protected _view: Panorama;
    protected _timer?: number;
    protected _state: State = 'pending';
    protected _isCanMove: boolean = false;
    protected _inertias: I[] = [];

    constructor(view: Panorama) {
        this._view = view;
    }

    protected abstract _frameUpdate(): void;

    protected _startFrameUpdate() {
        this._view.stop();
        !this._timer && this._frameUpdate();
    }

    protected _stopFrameUpdate(e: MouseEvent | TouchEvent) {
        if (this._timer) {
            cancelAnimationFrame(this._timer);
            this._state = 'pending';
            this._inertialEnd(e);
            delete this._timer;
        }

        this._isCanMove = false;
    }

    protected abstract _inertialEnd(e: MouseEvent | TouchEvent): void;

    get animator() {
        return this._view.handlerManager.getAnimator();
    }

    set animator(animator: Animator | undefined) {
        this._view.handlerManager.setAnimator(animator);
    }

    protected _initInertial() {
        const now = Date.now();
        let index = 0;
        for (let i = this._inertias.length - 1; i >= 0; i -= 1) {
            if (now - this._inertias[i][0] > 160) {
                index = i;
                break;
            }
        }
        this._inertias = this._inertias.slice(index + 1);
    }
}

export default AbstractGesture;
